package authorization.code.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;

@Configuration
// 开启认证服务器
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    /**
     * 用户认证 Manager
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.checkTokenAccess("isAuthenticated()");
    }

    /**
     * 设置 /oauth/check_token 端点，通过认证后可访问。
     * oauth/check_token 端点对应 CheckTokenEndpoint 类，用于校验访问令牌的有效性。
     * 在客户端访问资源服务器时，会在请求中带上访问令牌。
     * 在资源服务器收到客户端的请求时，会使用请求中的访问令牌，找授权服务器确认该访问令牌的有效性。
     * 通过 client-id 编号和 client-secret，授权服务器可以知道调用的来源以及正确性。
     * 这样，即使“坏人”拿到 Access Token ，但是没有 client-id 编号和 client-secret，也不能和授权服务器发生有效的交互
     * 友情提示：这里的认证，指的是使用 client-id + client-secret 进行的客户端认证，不要和用户认证混淆
     *
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory() // <4.1>
                .withClient("clientapp").secret("112233") // <4.2> Client 账号、密码。
                .authorizedGrantTypes("authorization_code") // <4.2> 授权码模式
                .redirectUris("http://127.0.0.1:9090/callback").scopes("read_userinfo", "read_contacts") // <4.2> 可授权的 Scope
        //                .and().withClient() // <4.3> 可以继续配置新的 Client
        ;
    }
}
